package rpg.engine.model;

import rpg.client.model.Position;
import rpg.client.model.Actor.Gender;
import rpg.util.Objects;
import rpg.util.Strings;

public class GameEffect {
    public static class Builder {
        private Type type = null;
        private Position toPosition = Position.VOID;

        private String storyID = "";

        public Builder() {
            super();
        }

        public GameEffect build() {
            return new GameEffect(this);
        }

        private String fromID = "";

        public Builder fromID(final String s) {
            fromID = Strings.trim(s);
            return this;
        }

        private String toID = "";

        public Builder toID(final String s) {
            toID = Strings.trim(s);
            return this;
        }

        public Builder storyID(final String s) {
            storyID = Strings.trim(s);
            return this;
        }

        public Builder to(final Position p) {
            toPosition = Objects.requireNonNull(p, "GameEffect.Builder.to");
            return this;
        }

        public Builder type(final String s) {
            type = Type.valueOf(s);
            return this;
        }

        public Builder type(final Type t) {
            type = Objects.requireNonNull(t, "GameEffect.Builder.type");
            return this;
        }
    }

    public enum Type {
        CHANGE_ACT {
            @Override
            public void accept(final GameEffect e) {
                Strings.requireNonEmpty(e.getStoryID(), this + ".storyID");
                Strings.requireNonEmpty(e.getFromID(), this + ".fromID");
            };
        },
        CREATE_EVENT {
            @Override
            public void accept(final GameEffect e) {
                Strings.requireNonEmpty(e.getStoryID(), this + ".storyID");
                Strings.requireNonEmpty(e.getFromID(), this + ".fromID");
            };
        },
        GENDER_CHANGE {
            @Override
            public void accept(final GameEffect e) {
                Strings.requireNonEmpty(e.getFromID(), this + ".fromID");
                Gender.valueOf(e.getToID());
            };
        },
        INVENTORY_ADD {
            @Override
            public void accept(final GameEffect e) {
                Strings.requireNonEmpty(e.getFromID(), this + ".fromID");
            };
        },
        INVENTORY_REMOVE {
            @Override
            public void accept(final GameEffect e) {
                Strings.requireNonEmpty(e.getFromID(), this + ".fromID");
            };
        },
        OBJECT_ACTIVATE {
            @Override
            public void accept(final GameEffect e) {
                Strings.requireNonEmpty(e.getStoryID(), this + ".storyID");
                Strings.requireNonEmpty(e.getFromID(), this + ".fromID");
            };
        },
        OBJECT_DEACTIVATE {
            @Override
            public void accept(final GameEffect e) {
                Strings.requireNonEmpty(e.getStoryID(), this + ".storyID");
                Strings.requireNonEmpty(e.getFromID(), this + ".fromID");
            };
        },
        NPC_MOVE {
            @Override
            public void accept(final GameEffect e) {
                Strings.requireNonEmpty(e.getFromID(), this + ".fromID");
                Objects.requireNonNull(e.getToPosition(), this + ".toPosition");
            };
        },
        PLAYER_MAP_CHANGE {
            @Override
            public void accept(final GameEffect e) {

            };
        },
        START_CHAT {
            @Override
            public void accept(final GameEffect e) throws IllegalArgumentException {
                Strings.requireNonEmpty(e.getStoryID(), this + ".storyID");
                Strings.requireNonEmpty(e.getFromID(), this + ".fromID");
            }
        },
        TOKEN_ADD {
            @Override
            public void accept(final GameEffect e) throws IllegalArgumentException {
                Strings.requireNonEmpty(e.getStoryID(), this + ".storyID");
                Strings.requireNonEmpty(e.getFromID(), this + ".fromID");
            }
        };

        abstract void accept(GameEffect effect) throws IllegalArgumentException;
    }

    private final Position toPosition;

    private final Type type;
    private final String fromID;

    private final String toID;

    public String getToID() {
        return toID;
    }

    private final String storyID;

    private GameEffect(final Builder builder) {
        super();
        type = Objects.requireNonNull(builder.type, "GameEffect.type");
        toPosition = builder.toPosition;
        storyID = builder.storyID;
        fromID = builder.fromID;
        toID = builder.toID;
        type.accept(this);
    }

    public String getFromID() {
        return fromID;
    }

    public String getStoryID() {
        return storyID;
    }

    public Position getToPosition() {
        return toPosition;
    }

    public Type getType() {
        return type;
    }

    @Override
    public String toString() {
        return "GameEffect: " + getType();
    }
}
